home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1995 March / macformat-022.iso / Shareware City / Developers / src / turbo-tcp-20b4-cpp.hqx / TurboTCP / TurboTCP source / CTCPResolverCall.cp < prev    next >
Encoding:
Text File  |  1994-07-03  |  23.6 KB  |  909 lines

  1. /*
  2. ** CTCPResolverCall.cp
  3. **
  4. **    TurboTCP support library
  5. **    TCP resolver call class
  6. **
  7. **    Copyright © 1993-94, FrostByte Design / Eric Scouten
  8. **    Some portions adapted from file “dnr.c” Copyright © 1988 by Apple Computer. All rights reserved.
  9. **
  10. */
  11.  
  12.  
  13. #include "CTCPResolverCall.h"
  14.  
  15. #include <Folders.h>
  16. #include <GestaltEqu.h>
  17. #include <Traps.h>
  18. #include "OSChecks.h"
  19. #include "TCLUtilities.h"
  20.  
  21.  
  22. #ifndef TCL_NO_TEMPLATES
  23.     class CTCPResolverCallList : public CPtrArray<CTCPResolverCall> {};
  24. #else
  25.     TM_DECLARE_CPtrArray(CTCPResolverCall);
  26. #endif
  27.  
  28.  
  29. // procedure code numbers for DNR code segment
  30.  
  31. #define OPENRESOLVER    1L
  32. #define CLOSERESOLVER    2L
  33. #define STRTOADDR        3L
  34. #define ADDRTOSTR        4L
  35. #define ENUMCACHE        5L
  36. #define ADDRTONAME    6L
  37. #define HINFO            7L
  38. #define MXINFO            8L
  39.  
  40.  
  41. //    —— class variables ——
  42.  
  43. Handle            CTCPResolverCall::macDNRcode = NULL;
  44. UniversalProcPtr    CTCPResolverCall::macDNRentry = NULL;
  45. #if USESROUTINEDESCRIPTORS
  46. ResultUPP            CTCPResolverCall::StrToAddrUPP = NewResultProc(CTCPResolverCall::PostponeStrToAddr);
  47. ResultUPP            CTCPResolverCall::AddrToNameUPP = NewResultProc(CTCPResolverCall::PostponeAddrToName);
  48. ResultProc2UPP    CTCPResolverCall::HInfoUPP = NewResultProc2Proc(CTCPResolverCall::PostponeHInfo);
  49. ResultProc2UPP    CTCPResolverCall::MXInfoUPP = NewResultProc2Proc(CTCPResolverCall::PostponeMXInfo);
  50. #endif
  51.  
  52.  
  53. TCL_DEFINE_CLASS_M0(CTCPResolverCall);
  54.  
  55.  
  56. /*______________________________________________________________________
  57. **
  58. ** interfaces to TCP DNR (adapted from latest <dnr.c>
  59. **
  60. */
  61.  
  62. // NOTE: The dnr.c file created for universal headers contained an error. All of the selectors
  63. // are treated by the DNR as long values, not short. This has been corrected in TurboTCP.
  64.  
  65. extern "C" {
  66.  
  67. typedef OSErr (*OpenResolverProcPtr)(long selector, char* fileName);
  68. typedef OSErr (*CloseResolverProcPtr)(long selector);
  69. typedef OSErr (*StrToAddrProcPtr)(long selector, char* hostName, struct hostInfo* rtnStruct,
  70.                                 long resultProc, char* userData);
  71. typedef OSErr (*AddrToStrProcPtr)(long selector, long address, char* hostName);
  72. typedef OSErr (*AddrToNameProcPtr)(long selector, unsigned long addr, struct hostInfo* rtnStruct,
  73.                                 long resultProc, char* userData);
  74. typedef OSErr (*HInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
  75.                                 long resultProc, char* userData);
  76. typedef OSErr (*MXInfoProcPtr)(long selector, char* hostName, struct returnRec* returnRecPtr,
  77.                                 long resultProc, char* userData);
  78.  
  79. };
  80.  
  81. #if USESROUTINEDESCRIPTORS
  82.  
  83. enum {
  84.     uppOpenResolverProcInfo = kCStackBased
  85.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  86.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  87.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  88. };
  89.  
  90. enum {
  91.     uppCloseResolverProcInfo = kCStackBased
  92.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  93.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  94. };
  95. enum {
  96.     uppStrToAddrProcInfo = kCStackBased
  97.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  98.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  99.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  100.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo*)))
  101.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  102.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  103. };
  104. enum {
  105.     uppAddrToStrProcInfo = kCStackBased
  106.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  107.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  108.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
  109.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(char*)))
  110. };
  111. enum {
  112.     uppAddrToNameProcInfo = kCStackBased
  113.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  114.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  115.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(unsigned long)))
  116.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct hostInfo*)))
  117.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  118.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  119.  
  120. };
  121. enum {
  122.     uppHInfoProcInfo = kCStackBased
  123.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  124.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  125.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  126.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec*)))
  127.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  128.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  129.  
  130. };
  131. enum {
  132.     uppMXInfoProcInfo = kCStackBased
  133.          | RESULT_SIZE(SIZE_CODE(sizeof(short)))
  134.          | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(long)))
  135.          | STACK_ROUTINE_PARAMETER(2, SIZE_CODE(sizeof(char*)))
  136.          | STACK_ROUTINE_PARAMETER(3, SIZE_CODE(sizeof(struct returnRec*)))
  137.          | STACK_ROUTINE_PARAMETER(4, SIZE_CODE(sizeof(long)))
  138.          | STACK_ROUTINE_PARAMETER(5, SIZE_CODE(sizeof(char*)))
  139.  
  140. };
  141.  
  142. typedef UniversalProcPtr OpenResolverUPP;
  143. typedef UniversalProcPtr CloseResolverUPP;
  144. typedef UniversalProcPtr StrToAddrUPP;
  145. typedef UniversalProcPtr AddrToStrUPP;
  146. typedef UniversalProcPtr AddrToNameUPP;
  147. typedef UniversalProcPtr HInfoUPP;
  148. typedef UniversalProcPtr MXInfoUPP;
  149.  
  150. #define    CallOpenResolverProc(userRoutine, selector, filename)    \
  151.         CallUniversalProc(userRoutine, uppOpenResolverProcInfo, selector, filename)
  152. #define    CallCloseResolverProc(userRoutine, selector)    \
  153.         CallUniversalProc(userRoutine, uppCloseResolverProcInfo, selector)
  154. #define    CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)    \
  155.         CallUniversalProc(userRoutine, uppStrToAddrProcInfo, selector, hostName, rtnStruct, resultProc, userData)
  156. #define    CallAddrToStrProc(userRoutine, selector, address, hostName)    \
  157.         CallUniversalProc(userRoutine, uppAddrToStrProcInfo, selector, address, hostName)
  158. #define    CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)    \
  159.         CallUniversalProc(userRoutine, uppAddrToNameProcInfo, selector, addr, rtnStruct, resultProc, userData)
  160. #define    CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  161.         CallUniversalProc(userRoutine, uppHInfoProcInfo, selector, hostName, returnRecPtr, resultProc, userData)
  162. #define    CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  163.         CallUniversalProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)
  164.  
  165. #else // #if USESROUTINEDESCRIPTORS
  166.  
  167. typedef OpenResolverProcPtr OpenResolverUPP;
  168. typedef CloseResolverProcPtr CloseResolverUPP;
  169. typedef StrToAddrProcPtr StrToAddrUPP;
  170. typedef AddrToStrProcPtr AddrToStrUPP;
  171. typedef AddrToNameProcPtr AddrToNameUPP;
  172. typedef HInfoProcPtr HInfoUPP;
  173. typedef MXInfoProcPtr MXInfoUPP;
  174.  
  175. #define    CallOpenResolverProc(userRoutine, selector, filename)    \
  176.         (*((OpenResolverProcPtr) userRoutine))(selector, filename)
  177. #define    CallCloseResolverProc(userRoutine, selector)    \
  178.         (*((CloseResolverProcPtr) userRoutine))(selector)
  179. #define    CallStrToAddrProc(userRoutine, selector, hostName, rtnStruct, resultProc, userData)    \
  180.         (*((StrToAddrProcPtr) userRoutine))(selector, hostName, rtnStruct, resultProc, userData)
  181. #define    CallAddrToStrProc(userRoutine, selector, address, hostName)    \
  182.         (*((AddrToStrProcPtr) userRoutine))(selector, address, hostName)
  183. #define    CallAddrToNameProc(userRoutine, selector, addr, rtnStruct, resultProc, userData)    \
  184.         (*((AddrToNameProcPtr) userRoutine))(selector, addr, rtnStruct, resultProc, userData)
  185. #define    CallHInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  186.         (*((HInfoProcPtr) userRoutine))(selector, hostName, returnRecPtr, resultProc, userData)
  187. #define    CallMXInfoProc(userRoutine, selector, hostName, returnRecPtr, resultProc, userData)    \
  188.         (*((MXInfoProcPtr) userRoutine))(selector, hostName, returnRecPtr, resultProc, userData)
  189.  
  190. #endif // #ifdef USESROUTINEDESCRIPTORS
  191.  
  192.  
  193. //    —— constructor/destructor ——
  194.  
  195. /*______________________________________________________________________
  196. **
  197. ** constructor
  198. **
  199. **    Initialize the resolver object.
  200. **
  201. */
  202.  
  203. CTCPResolverCall::CTCPResolverCall(CTCPEndpoint& theEndpoint)
  204.     : itsEndpoint(&theEndpoint), qEntry(this)
  205.  
  206. {
  207.     // clear variables
  208.     
  209.     inUse = FALSE;
  210.     disposeOnCompletion = FALSE;
  211.     pendingNotify = notifNone;
  212.     qEntry.qType = resolverCall;
  213.     TCL_END_CONSTRUCTOR;
  214. }
  215.  
  216.  
  217. /*______________________________________________________________________
  218. **
  219. ** destructor
  220. **
  221. **    DO NOT CALL THIS METHOD! Use Dispose() instead.
  222. **
  223. */
  224.  
  225. CTCPResolverCall::~CTCPResolverCall()
  226. {
  227.     TCL_START_DESTRUCTOR;
  228. }
  229.  
  230.  
  231. /*______________________________________________________________________
  232. **
  233. ** Dispose
  234. **
  235. **    Get rid of the resolver object. If a resolver operation is in progress, will dispose of
  236. **    itself when the current resolver operation is completed.
  237. **
  238. **    Use Dispose() instead of destructor since the object may need to remain around for a
  239. **    while.
  240. **
  241. */
  242.  
  243. void CTCPResolverCall::Dispose()
  244.  
  245. {
  246.     if (inUse)
  247.         disposeOnCompletion = TRUE;
  248.     else
  249.         delete this;
  250. }
  251.  
  252.  
  253. //    —— initiate resolver calls ——
  254.  
  255. /*______________________________________________________________________
  256. **
  257. ** DoStrToAddr
  258. **
  259. **    Get the IP address of a host named by a DNS or dotted decimal string. Completion is
  260. **    handled by HandleStrToAddr.
  261. **
  262. **        theHostName (char*):    whose IP address do we need?
  263. **
  264. */
  265.  
  266. void CTCPResolverCall::DoStrToAddr(char* theHostName)
  267.  
  268. {
  269.     OSErr theResult;
  270.     
  271.     if (inUse)
  272.         FailOSErr(resolverInUse);
  273.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  274.         FailOSErr(noResolverErr);
  275.     
  276.     inUse = TRUE;
  277.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  278.     BlockMove(theHostName, &hostName, 255);
  279.  
  280.     #if USESROUTINEDESCRIPTORS                        // seems to be buggy here…
  281.         theResult = CallStrToAddrProc(macDNRentry, STRTOADDR, (char*) &hostName, &theHostInfo,
  282.                                 (long) StrToAddrUPP, (char*) this);
  283.     #else
  284.         theResult = CallStrToAddrProc(macDNRentry, STRTOADDR, (char*) &hostName, &theHostInfo,
  285.                                 (long) &PostponeStrToAddr, (char*) this);
  286.     #endif
  287.  
  288.  
  289.     // if call was completed immediately (with error or not), process it immediately
  290.     
  291.     if (theResult != cacheFault) {
  292.         inUse = FALSE;
  293.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  294.         HandleStrToAddr();
  295.     }
  296. }
  297.  
  298.  
  299. /*______________________________________________________________________
  300. **
  301. ** DoAddrToStr (static method)
  302. **
  303. **    Convert an IP address to dotted decimal notation. This call can be used while the resolver
  304. **    object is otherwise in use, and is completed immediately.
  305. **
  306. **        theIPaddr (ip_addr):    the address to convert
  307. **        theString (char*):    where to send the completed string (min. 16 chars)
  308. **
  309. */
  310.  
  311. void CTCPResolverCall::DoAddrToStr(ip_addr theIPaddr, char* theString)
  312.  
  313. {
  314.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  315.         FailOSErr(noResolverErr);
  316.     CallAddrToStrProc(macDNRentry, ADDRTOSTR, theIPaddr, theString);
  317. }
  318.  
  319.  
  320. /*______________________________________________________________________
  321. **
  322. ** DoAddrToName
  323. **
  324. **    Get the canonical name of a host as specified by IP address. Completion is handled by
  325. **    HandleAddrToName method.
  326. **
  327. **        theIPaddr (ip_addr):    the IP address to query
  328. **
  329. */
  330.  
  331. void CTCPResolverCall::DoAddrToName(ip_addr theIPaddr)
  332.  
  333. {
  334.     OSErr theResult;
  335.     
  336.     if (inUse)
  337.         FailOSErr(resolverInUse);
  338.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  339.         FailOSErr(noResolverErr);
  340.     
  341.     inUse = TRUE;
  342.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  343.  
  344.     #if USESROUTINEDESCRIPTORS                        // seems to be buggy here…
  345.         theResult = CallAddrToNameProc(macDNRentry, ADDRTONAME, theIPaddr, &theHostInfo,
  346.                                     (long) AddrToNameUPP, (char*) this);
  347.     #else
  348.         theResult = CallAddrToNameProc(macDNRentry, ADDRTONAME, theIPaddr, &theHostInfo,
  349.                                     (long) &PostponeAddrToName, (char*) this);
  350.     #endif
  351.  
  352.  
  353.     // if call was completed immediately (with error or not), process it immediately
  354.     
  355.     if (theResult != cacheFault) {
  356.         inUse = FALSE;
  357.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  358.         HandleAddrToName();
  359.     }
  360. }
  361.  
  362.  
  363. /*______________________________________________________________________
  364. **
  365. ** DoHInfo
  366. **
  367. **    Get the CPU type and operating system type of a remote host. Completion is handled by
  368. **    HandleHInfo.
  369. **
  370. **        theHostName (char*):    who we askin’ ‘bout anyway?
  371. **
  372. */
  373.  
  374. void CTCPResolverCall::DoHInfo(char* theHostName)
  375.  
  376. {
  377.     OSErr theResult;
  378.     
  379.     if (inUse)
  380.         FailOSErr(resolverInUse);
  381.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  382.         FailOSErr(noResolverErr);
  383.     
  384.     inUse = TRUE;
  385.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  386.     BlockMove(theHostName, &hostName, 255);
  387.  
  388.     #if USESROUTINEDESCRIPTORS                        // seems to be buggy here…
  389.         theResult = CallHInfoProc(macDNRentry, HINFO, (char*) &hostName, &theHMXInfo,
  390.                                 (long) HInfoUPP, (char*) this);
  391.     #else
  392.         theResult = CallHInfoProc(macDNRentry, HINFO, (char*) &hostName, &theHMXInfo,
  393.                                 (long) &PostponeHInfo, (char*) this);
  394.     #endif
  395.  
  396.  
  397.     // if call was completed immediately (with error or not), process it immediately
  398.     
  399.     if (theResult != cacheFault) {
  400.         inUse = FALSE;
  401.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  402.         HandleHInfo();
  403.     }
  404. }
  405.  
  406.  
  407. /*______________________________________________________________________
  408. **
  409. ** DoMXInfo
  410. **
  411. **    Get the mailbox exchange (MX) info of a remote host. Completion is handled by
  412. **    HandleMXInfo.
  413. **
  414. **        theHostName (char*):    who we askin’ ‘bout anyway?
  415. **
  416. */
  417.  
  418. void CTCPResolverCall::DoMXInfo(char* theHostName)
  419.  
  420. {
  421.     OSErr theResult;
  422.     
  423.     if (inUse)
  424.         FailOSErr(resolverInUse);
  425.     if (!(CTCPDriver::gTCPDriver)->CheckResolver())
  426.         FailOSErr(noResolverErr);
  427.     
  428.     inUse = TRUE;
  429.     (CTCPDriver::gTCPDriver)->RegisterActiveResolver(this);
  430.     BlockMove(theHostName, &hostName, 255);
  431.     #if USESROUTINEDESCRIPTORS                        // seems to be buggy here…
  432.         theResult = CallMXInfoProc(macDNRentry, MXINFO, (char*) &hostName, &theHMXInfo,
  433.                                 (long) MXInfoUPP, (char*) this);
  434.     #else
  435.         theResult = CallMXInfoProc(macDNRentry, MXINFO, (char*) &hostName, &theHMXInfo,
  436.                                 (long) &PostponeMXInfo, (char*) this);
  437.     #endif
  438.  
  439.  
  440.     // if call was completed immediately (with error or not), process it immediately
  441.     
  442.     if (theResult != cacheFault) {
  443.         inUse = FALSE;
  444.         (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  445.         HandleMXInfo();
  446.     }
  447. }
  448.  
  449.  
  450. //    —— respond to completion of resolver calls ——
  451.  
  452. /*______________________________________________________________________
  453. **
  454. ** ProcessNotify (private method)
  455. **
  456. **    Handles any notifications passed to the resolver. This routine is free of interrupt-level
  457. **    constraints.
  458. **
  459. */
  460.  
  461. void CTCPResolverCall::ProcessNotify(void)
  462.  
  463. {
  464.     // free this resolver object for future use
  465.     
  466.     (CTCPDriver::gTCPDriver)->RemoveActiveResolver(this);
  467.     inUse = FALSE;    
  468.     
  469.  
  470.     // dispatch notification to appropriate routine
  471.     
  472.     switch (pendingNotify) {
  473.         case notifStrToAddr:
  474.             HandleStrToAddr();
  475.             break;
  476.             
  477.         case notifAddrToName:
  478.             HandleAddrToName();
  479.             break;
  480.             
  481.         case notifHInfo:
  482.             HandleHInfo();
  483.             break;
  484.             
  485.         case notifMXInfo:
  486.             HandleMXInfo();
  487.     }
  488.     
  489.     
  490.     // if someone attempted to dispose this earlier, do it now
  491.     
  492.     if (disposeOnCompletion)
  493.         delete this;
  494.     
  495. }
  496.  
  497.  
  498. //    —— open/close TCP resolver ——
  499.  
  500. /*______________________________________________________________________
  501. **
  502. ** OpenResolver (private static method)
  503. **
  504. **    Find the MacTCP DNR code resource and read it. Save the location of the resolver resource
  505. **    for later use.
  506. **
  507. */
  508.  
  509. void CTCPResolverCall::OpenResolver()
  510.  
  511. {
  512.     short    vRefNum;
  513.     short    refnum;
  514.     long        dirID;
  515.     short    fRef;
  516.     OSErr    rc;
  517.     
  518.     
  519.     // is the resolver already there?
  520.     
  521.     if (macDNRentry)
  522.         return;
  523.  
  524.  
  525.     // open the MacTCP driver to get DNR resources
  526.  
  527.     TRY {
  528.         refnum = OpenTheDNR();
  529.     }
  530.     CATCH {
  531.         NO_PROPAGATE;                    // ignore failures since the resource may
  532.                                         // have been installed in the System file
  533.                                         // (if running on a Mac 512Ke)
  534.     }
  535.     ENDTRY;
  536.  
  537.  
  538.     // load the DNR resource package
  539.     
  540.     macDNRcode = GetIndResource('dnrp', 1);
  541.     FailNIL(macDNRcode);
  542.     DetachResource(macDNRcode);
  543.  
  544.     if (refnum != -1)
  545.         CloseResFile(refnum);
  546.  
  547.         
  548.     // lock the DNR resource since it cannot be relocated while opened
  549.  
  550.     MoveHHi(macDNRcode);
  551.     HLock(macDNRcode);
  552.     macDNRentry = (UniversalProcPtr) *macDNRcode;
  553.  
  554.  
  555.     // check for “hosts” file in System Folder (BRB)
  556.  
  557.     GetSystemFolder(&vRefNum, &dirID);
  558.     rc = HOpen(vRefNum, dirID, "\pHosts", fsRdPerm, &fRef);
  559.     switch (rc) {
  560.         case noErr:
  561.             FSClose(fRef);
  562.             break;
  563.             
  564.         case fnfErr:
  565.             if ((rc = HCreate(vRefNum, dirID, "\pHosts", 'ttxt', 'TEXT')) != noErr)
  566.                 ErrorAlert(rc, SpecifyMsg(1001, 1));
  567.             break;
  568.             
  569.         default:
  570.             break;
  571.     }
  572.  
  573.  
  574.     // ask the DNR resource to open the resolver
  575.  
  576.     rc = CallOpenResolverProc(macDNRentry, OPENRESOLVER, NULL);
  577.                                             // send it a null hosts file name
  578.     if (rc != noErr) {
  579.         HUnlock(macDNRcode);                    // problem with open resolver, flush DNR resource
  580.         DisposHandle(macDNRcode);
  581.         macDNRcode = NULL;
  582.         macDNRentry = NULL;
  583.         FailOSErr(rc);                            // signal failure of DNR
  584.     }
  585.  
  586. }
  587.  
  588.  
  589. /*______________________________________________________________________
  590. **
  591. ** CloseResolver (private static method)
  592. **
  593. **    Shut down the DNR code resource. Does nothing if the resolver was never loaded.
  594. **
  595. */
  596.  
  597. void CTCPResolverCall::CloseResolver()
  598.  
  599. {
  600.  
  601.     // ensure that we had a resolver to begin with
  602.     
  603.     if (macDNRentry == NULL)
  604.         return;
  605.  
  606.  
  607.     // call CloseResolver function in DNR
  608.  
  609.     CallCloseResolverProc(macDNRentry, CLOSERESOLVER);
  610.  
  611.  
  612.     // release the DNR code resource
  613.  
  614.     HUnlock(macDNRcode);
  615.     DisposHandle(macDNRcode);
  616.     macDNRcode = NULL;
  617.     macDNRentry = NULL;
  618.  
  619. }
  620.  
  621.  
  622. /*______________________________________________________________________
  623. **
  624. ** OpenTheDNR (private static method)
  625. **
  626. **    Search in several places for the MacTCP DNR code resource. Tries the Control Panels
  627. **    folder and the System folder.
  628. **
  629. **        return (short):    reference number to resource file
  630. **
  631. */
  632.  
  633. short CTCPResolverCall::OpenTheDNR()
  634.  
  635. {
  636.     short    refnum;
  637.     short    vRefNum;
  638.     long        dirID;
  639.     
  640.     
  641.     // first search Control Panels for MacTCP 1.1.x
  642.  
  643.     GetCPanelFolder(&vRefNum, &dirID);
  644.     refnum = SearchFolderForDNRP('cdev', 'ztcp', vRefNum, dirID);
  645.     if (refnum != -1)
  646.         return refnum;
  647.     
  648.     
  649.     // next search System Folder for MacTCP 1.0.x
  650.  
  651.     GetSystemFolder(&vRefNum, &dirID);
  652.     refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
  653.     if (refnum != -1)
  654.         return refnum;
  655.  
  656.  
  657.     // finally, search Control Panels for MacTCP 1.0.x
  658.  
  659.     GetCPanelFolder(&vRefNum, &dirID);
  660.     refnum = SearchFolderForDNRP('cdev', 'mtcp', vRefNum, dirID);
  661.     if (refnum != -1)
  662.         return refnum;
  663.     
  664.     return -1;
  665.  
  666. }
  667.  
  668.  
  669. /*______________________________________________________________________
  670. **
  671. ** SearchFolderForDNRP (private static method)
  672. **
  673. **    Search a folder for files that might contain the 'dnrp' resource.
  674. **
  675. **        targetType (OSType):    file type that we are looking for
  676. **        targetCreator (OSType):    file creator    ""        ""
  677. **        vRefNum (short):        volume ref num
  678. **        dirID (long):            directory number on the volume
  679. **
  680. **        return (short):            the refnum of the file if found, -1 if not found
  681. **
  682. */
  683.  
  684. short CTCPResolverCall::SearchFolderForDNRP(long targetType, long targetCreator,
  685.                                     short vRefNum, long dirID)
  686.  
  687. {
  688.     HParamBlockRec    fi;
  689.     Str255            filename;
  690.     short            refnum;
  691.     
  692.     
  693.     // initialize our search mechanism
  694.     
  695.     fi.fileParam.ioCompletion = nil;
  696.     fi.fileParam.ioNamePtr = filename;
  697.     fi.fileParam.ioVRefNum = vRefNum;
  698.     fi.fileParam.ioDirID = dirID;
  699.     fi.fileParam.ioFDirIndex = 1;
  700.     
  701.     
  702.     // keep looking till we run out of files
  703.     
  704.     while (PBHGetFInfo(&fi, false) == noErr) {
  705.     
  706.         // scan the folder for files that match our type & creator
  707.  
  708.         if (fi.fileParam.ioFlFndrInfo.fdType == targetType &&
  709.             fi.fileParam.ioFlFndrInfo.fdCreator == targetCreator) {
  710.  
  711.             // type/creator match, look for the resource
  712.             
  713.             refnum = HOpenResFile(vRefNum, dirID, filename, fsRdPerm);
  714.             if (GetIndResource('dnrp', 1) == NULL)
  715.                 CloseResFile(refnum);
  716.             else
  717.                 return refnum;
  718.         }
  719.  
  720.         // no match or no resource, try next file in folder
  721.  
  722.         fi.fileParam.ioFDirIndex++;
  723.         fi.fileParam.ioDirID = dirID;                // PBHGetFInfo() clobbers ioDirID
  724.     }
  725.     
  726.     return -1;                                    // nothing found
  727.  
  728. }    
  729.  
  730.  
  731. /*______________________________________________________________________
  732. **
  733. ** GetSystemFolder (private static method)
  734. **
  735. **    Return the ID of the current system folder.
  736. **
  737. **        vRefNumP (short *):        returns volume ref number
  738. **        dirIDP (long *):            returns directory ID
  739. **
  740. */
  741.  
  742. void CTCPResolverCall::GetSystemFolder(short* vRefNumP, long* dirIDP)
  743.  
  744. {
  745.     SysEnvRec    info;
  746.     long            wdProcID;
  747.     
  748.     SysEnvirons(1, &info);
  749.     if (GetWDInfo(info.sysVRefNum, vRefNumP, dirIDP, &wdProcID) != noErr) {
  750.         *vRefNumP = 0;
  751.         *dirIDP = 0;
  752.     }
  753. }
  754.  
  755.  
  756. /*______________________________________________________________________
  757. **
  758. ** GetCPanelFolder (private static method)
  759. **
  760. **    Return the ID of the current “Control Panels” folder.
  761. **
  762. **        vRefNumP (short*):        returns volume ref number
  763. **        dirIDP (long*):            returns directory ID
  764. **
  765. */
  766.  
  767. void CTCPResolverCall::GetCPanelFolder(short* vRefNumP, long* dirIDP)
  768.  
  769. {
  770.     Boolean    hasFolderMgr = false;
  771.     long        feature;
  772.     
  773.     
  774.     // see if we have the Folder Manager available
  775.     
  776.     if (TrapAvailable((short) _Gestalt))
  777.         if (Gestalt(gestaltFindFolderAttr, &feature) == noErr)
  778.             hasFolderMgr = TRUE;
  779.  
  780.  
  781.     // if folder manager, use it; else return system folder
  782.         
  783.     if (!hasFolderMgr) {
  784.         GetSystemFolder(vRefNumP, dirIDP);
  785.         return;
  786.     }
  787.     else {
  788.         if (FindFolder(kOnSystemDisk, kControlPanelFolderType,
  789.                     kDontCreateFolder, vRefNumP, dirIDP) != noErr) {
  790.             *vRefNumP = 0;
  791.             *dirIDP = 0;
  792.         }
  793.     }
  794.  
  795. }
  796.  
  797.  
  798. /***********************************************************************
  799. ************************************************************************
  800. **
  801. **    INTERRUPT-LEVEL routines follow. These routines cannot make memory allocations, cannot make
  802. **    synchronous TCP calls, and cannot use the Think C profiler.
  803. **
  804. */
  805.  
  806. #ifndef __MWERKS__
  807. //#pragma options(!profile)
  808. #else
  809. #pragma profile off
  810. #endif
  811.  
  812.  
  813. //     —— interrupt-level methods: delay processing for non-interrupt status ——
  814.  
  815. /*______________________________________________________________________
  816. **
  817. ** PostponeNotify (private static method)
  818. **
  819. **    Respond to notification that a DNR call was completed. Delays processing of notification
  820. **    until the next net-event call. This method merely logs the kind of notification and adds this
  821. **    resolver to the list of resolvers to be processed next time through the event loop.
  822. **
  823. **        theNotifType (NotifType):    which resolver call was completed
  824. **
  825. */
  826.  
  827. void CTCPResolverCall::PostponeNotify(NotifType theNotifType)
  828.  
  829. {
  830.     pendingNotify = theNotifType;
  831.     Enqueue((QElemPtr) &qEntry, &((CTCPDriver::gTCPDriver)->asyncQueue));
  832. }
  833.  
  834.  
  835. /*______________________________________________________________________
  836. **
  837. ** PostponeStrToAddr (private static method)
  838. **
  839. **    Respond to notification that the StrToAddr call was completed.
  840. **
  841. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  842. **        userDataPtr (char*):    user data pointer (assumed to be CTCPResolver*)
  843. **
  844. */
  845.  
  846. pascal void CTCPResolverCall::PostponeStrToAddr(struct hostInfo* hostInfoPtr, char* userDataPtr)
  847.  
  848. {
  849.     if (userDataPtr)
  850.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifStrToAddr);
  851. }
  852.  
  853.  
  854. /*______________________________________________________________________
  855. **
  856. ** PostponeAddrToName (private static method)
  857. **
  858. **    Respond to notification that the AddrToName call was completed.
  859. **
  860. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  861. **        userDataPtr (char*):    user data pointer (assumed to be CTCPResolver*)
  862. **
  863. */
  864.  
  865. pascal void CTCPResolverCall::PostponeAddrToName(struct hostInfo* hostInfoPtr, char* userDataPtr)
  866.  
  867. {
  868.     if (userDataPtr)
  869.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifAddrToName);
  870. }
  871.  
  872.  
  873. /*______________________________________________________________________
  874. **
  875. ** PostponeHInfo (private static method)
  876. **
  877. **    Respond to notification that the HInfo call was completed.
  878. **
  879. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  880. **        userDataPtr (char *):    user data pointer (assumed to be CTCPResolver *)
  881. **
  882. */
  883.  
  884. pascal void CTCPResolverCall::PostponeHInfo(struct returnRec* returnRecPtr, char* userDataPtr)
  885.  
  886. {
  887.     if (userDataPtr)
  888.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifHInfo);
  889. }
  890.  
  891.  
  892. /*______________________________________________________________________
  893. **
  894. ** PostponeMXInfo (private static method)
  895. **
  896. **    Respond to notification that the MXInfo call was completed.
  897. **
  898. **        hostInfoPtr (…):        pointer to the DNR data structure (ignored)
  899. **        userDataPtr (char*):    user data pointer (assumed to be CTCPResolver*)
  900. **
  901. */
  902.  
  903. pascal void CTCPResolverCall::PostponeMXInfo(struct returnRec* returnRecPtr, char* userDataPtr)
  904.  
  905. {
  906.     if (userDataPtr)
  907.         ((CTCPResolverCall*) userDataPtr)->PostponeNotify(notifMXInfo);
  908. }
  909.